#include "NetworkHandler.hpp"
NetworkHandler* NetworkHandler::currentInstance = 0;

NetworkHandler* NetworkHandler::getInstance() {
    return currentInstance;
}

NetworkHandler::NetworkHandler(std::string sAddr, unsigned short sPort) {
    currentInstance = this;

    MessageQueue::initialize(&serverTime);
    outQueue = new MessageQueue();
	inQueue = new MessageQueue();
    address = sf::IpAddress(sAddr);
    out_port = sPort;
    bind(50012);
}

/** 
* Bind the network handler to specified port. Opens socket.
*/
void NetworkHandler::bind(unsigned short port){
    in_port = port;
    socket.unbind();
    socket.bind(in_port);
    socket.setBlocking(false);
}

/** 
* Set the time at server.
*/
void NetworkHandler::setServerTime(uint32_t time) {
    serverTime.serverTime = time;
    serverTime.serverTimer.restart();
}

/** 
* Set the index of the client in the server.
*/
void NetworkHandler::setClientIndex(byte index) {
    clientIndex = index;
}

/** 
* Add message to send to server.
* @param code Message code.
* @param data Message data.
* @return Iterator pointing to position of added message.
*/
MessageIterator& NetworkHandler::addMessage(Message::MessageCode code, void* data){
	if(outQueue->size == 0 && (Message::messageGroup(code) == Message::g_Critical ||
		Message::messageGroup(code) == Message::g_Normal)){
			outQueue->createMessage(Message::m_c_SenderInfo, &clientIndex);
	}
	return outQueue->createMessage(code, data);
}

/** 
* Send any messages in the queue if they are ready to be sent.
*/
bool NetworkHandler::sendMessages() {
    if (outQueue->sendQueue(socket, address, out_port) == sf::Socket::Done) {
        return true;
    } else {
        return false;
    }
}

/** 
* Force send any messages in the queue.
*/
bool NetworkHandler::forceSendMessages() {
    if (outQueue->forceSendQueue(socket, address, out_port) == sf::Socket::Done) {
        return true;
    } else {
        return false;
    }
}

/** 
* Get messages from server.
* @return MessageQueue with any messages received or 0 if none received.
*/
MessageQueue* NetworkHandler::getServerMessages() {
    sf::Packet receivedPacket;
    sf::IpAddress rAddress;
    unsigned short rPort;

    if (socket.receive(receivedPacket, rAddress, rPort) == sf::Socket::Done) {
		inQueue->parsePacket(receivedPacket);
        return inQueue;
    }
    return 0;
}

/** 
* Lock and wait while attempting to get messages from server. Waits for specified time.
* See getServerMessages for more information.
*/
MessageQueue* NetworkHandler::getServerMessagesWait(unsigned int timeout) {
    sf::Clock timer;
    timer.restart();
    MessageQueue* returnQueue = getServerMessages();

	//Attempt reading messages until timeout reached or a message received.
    while (timer.getElapsedTime().asMilliseconds() < timeout && returnQueue == 0) {
        returnQueue = getServerMessages();
        sf::sleep(sf::milliseconds(1));
    }
    return returnQueue;
}

/** 
* Close connection with server.
*/
void NetworkHandler::closeConnection() {
    socket.unbind();
}

NetworkHandler::~NetworkHandler() {
    currentInstance = 0;
    delete outQueue;
    outQueue = 0;
	delete inQueue;
	inQueue = 0;
}